
public class Test {
    public static void main(String[] args) throws Exception {
        Light light = new Light();
        Remote remote = new Remote();

        Command on = new LightOnCommand(light);
        Command off = new LightOffCommand(light);

        remote.press(on); // 开灯
        remote.press(off); // 关灯
        remote.undo(); // 再开回来
    }

}

// 命令模式 = “把请求封装成对象”
// 拆开「请求」和「执行」：
// 调用者只发命令，不用知道谁来执行、怎么执行
// 命令对象内部持有「接收者」引用，自己找办法把事情办了
// 于是可以排队、撤销、重做、日志、宏命令……全变成操作对象列表

// 接收者（真正干活的）
class Light {
    void on() {
        System.out.println("Light is ON");
    }

    void off() {
        System.out.println("Light is OFF");
    }
}

// 命令接口
interface Command {
    void execute(); // 执行

    void undo(); // 撤销
}

// 具体命令（封装请求 + 接收者）
class LightOnCommand implements Command {
    private final Light light;

    LightOnCommand(Light light) {
        this.light = light;
    }

    public void execute() {
        light.on();
    }

    public void undo() {
        light.off();
    }
}

class LightOffCommand implements Command {
    private final Light light;

    LightOffCommand(Light light) {
        this.light = light;
    }

    public void execute() {
        light.off();
    }

    public void undo() {
        light.on();
    }
}

// 调用者（遥控器）
class Remote {
    private Command history; // 记录最后一次，用于撤销

    void press(Command cmd) {
        history = cmd;
        cmd.execute();
    }

    void undo() {
        if (history != null)
            history.undo();
    }
}